/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * All Rights Researved.
 *
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
 *
 *
 * @author: jin Chen
 * @date: Jun 20, 2003
 * @version: $VERSION$
 */
package edu.psu.geovista.app.plot.axis;

import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ComponentUI;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class MTYAxisUI extends BasicAxisUI{
    MTYAxis axis;
    protected  SlideRuler ruler;
    //ChangeHandler changeHandler;
    protected ThumbListener tmbl;
    HashMap trMap=new HashMap();//thumb to range

    public MTYAxisUI(MTYAxis axis) {
        super(axis);
    }

    /////////////////////////////////////////////////////////////////////////////
    // ComponentUI Interface Implementation methods
    /////////////////////////////////////////////////////////////////////////////
    public static ComponentUI createUI(JComponent b)    {
        return new MTYAxisUI((MTYAxis)b);
    }

    public void installUI(JComponent c)   {
        this.axis=(MTYAxis)c;
        //this.ruler =(SlideRuler)axis.getRuler() ;
         //do initial here
        this.tmbl =new ThumbListener();
        this.axisStateMonitor=new ChangeHandler();

        ruler=new SlideRuler(edu.psu.geovista.app.plot.ruler.Ruler.VERTICAL, axis.getActiveSize() , axis.getAxisLocation() ,axis.getDataRange() );
        ruler.setStroke(new BasicStroke(3));
        ruler.setThumbs(this.createThumbs(axis) );
        this.updateRuler() ;    //set thumbs' value

        this.installListeners(axis);


    }
    protected void installListeners(MTYAxis axis){
        axis.addMouseListener(tmbl);
        axis.addMouseMotionListener(tmbl);
        axis.getModel().addChangeListener(this.axisStateMonitor );
    }
    public void paint( Graphics g, JComponent c )   {
        if(ruler!=null)
        this.ruler.paintComponent(g);

    }
    public void uninstallUI(JComponent c) {
        this.axis =null;
        this.tmbl =null;
        this.ruler =null;
    }
    /*******************************************************************************************************
     *
     *******************************************************************************************************/
    /**
     *  create thumbs based on the axis's range values
     */
    private ThumbList createThumbs(BasicAxis axis){
        ThumbList thumbs=new ThumbList();
        //Extreme lineShowRange=axis.getShowRange() ;  //control line display range of axis being configured
        //Extreme axisShowRange=axis.getTickRange() ; //the tick range of axis being configured

        Thumb et,eb,wt,wb;
        //Extreme r=this.getRange() ;
        et=new Thumb(Thumb.EAST,MTYAxis.THUMB_COLOR_WEST ,SlideRuler.ET); //Color.green
        et.setLocType(Thumb.TOP );
        eb=new Thumb(Thumb.EAST,MTYAxis.THUMB_COLOR_WEST,SlideRuler.EB);
        eb.setLocType(Thumb.BTTM );
        wt=new Thumb(Thumb.WEST,MTYAxis.THUMB_COLOR_EAST,SlideRuler.WT);
        wt.setLocType(Thumb.TOP );
        wb=new Thumb(Thumb.WEST,MTYAxis.THUMB_COLOR_EAST,SlideRuler.WB);
        wb.setLocType(Thumb.BTTM );
        /*
        et.setValue(lineShowRange.getMax());
        eb.setValue(lineShowRange.getMin() );
        wt.setValue(axisShowRange.getMax());
        wb.setValue(axisShowRange.getMin());    */

        thumbs.put(et.getName(), et);
        thumbs.put(eb.getName(), eb);
        thumbs.put(wt.getName(), wt);
        thumbs.put(wb.getName(), wb);

       //map
        //Extreme lineShowRange=axis.getShowRange() ;  //control line display range of axis being configured
        //Extreme axisShowRange=axis.getTickRange() ;


        trMap.put(et,axis.getShowRange());
        trMap.put(eb,axis.getShowRange());
        trMap.put(wt,axis.getTickRange() );
        trMap.put(wb,axis.getTickRange() );
        Set keys=trMap.keySet() ;
            Iterator iter=keys.iterator() ;
            while(iter.hasNext() ){
               Thumb thumb  =(Thumb)iter.next() ;
               Range range=(Range)trMap.get(thumb);
               //System.out.println( thumb.getName() +" locType:"+thumb.getLocType() +" get range:"+range);

               if(thumb.getLocType() ==Thumb.TOP ){
                   thumb.setValue(range.getMax() );
               }
               else if (thumb.getLocType() ==Thumb.BTTM ){
                    thumb.setValue(range.getMin() );
               }

            }


        return thumbs;

    }

    /**
     * Ruler initialize&update
     * subclass need reimplement the method based on ruler type
     */
    protected  void updateRuler(){
        if (ruler!=null){
            this.ruler.setLength(this.axis.getActiveSize() );
            this.ruler.setTickRange(this.axis.getTickRange() );
            this.ruler.setLocation(this.axis.getAxisLocation() );
            /*
            Collection c=trMap.values() ;
            int csize=c.size() ;
            Set keys=trMap.keySet() ;
            Iterator iter=keys.iterator() ;
            while(iter.hasNext() ){
               Thumb thumb  =(Thumb)iter.next() ;
               Extreme range=(Extreme)trMap.get(thumb);
               System.out.println( thumb.getName() +" locType:"+thumb.getLocType() +" get range:"+range);

               if(thumb.getLocType() ==Thumb.TOP ){
                   thumb.setValue(range.getMax() );
               }
               else if (thumb.getLocType() ==Thumb.BTTM ){
                    thumb.setValue(range.getMin() );
               }

            }           */


            Thumb et,eb,wt,wb;
            et=this.ruler.getThumb(SlideRuler.ET);
            eb=this.ruler.getThumb(SlideRuler.EB);
            wt=this.ruler.getThumb(SlideRuler.WT);
            wb=this.ruler.getThumb(SlideRuler.WB);

            //this.axis.setModel(null);
           // this.axis.setModel(new MTYAxisModel());
            Range showRange=axis.getTargetAxisShowRange() ;  //control line display range of axis being configured
            Range tickRange=axis.getTargetAxisTickRange() ; //the tick range of axis being configured

            et.setValue(showRange.getMax());
            eb.setValue(showRange.getMin() );
            wt.setValue(tickRange.getMax());
            wb.setValue(tickRange.getMin());
            /*
            System.out.println("lineShowRange.getMax()"+lineShowRange.getMax());
            System.out.println("lineShowRange.getMin()"+lineShowRange.getMin());
            System.out.println("axisShowRange.getMax()"+axisShowRange.getMax());
            System.out.println("axisShowRange.getMin()"+axisShowRange.getMin());                */
        }

    }
    /*******************************************************************************************************
     *                Track thumbs
     *******************************************************************************************************/
    /**
     *  don't set tb directly, tb's value will be update after range changed
     *  Change target value based on the values of the ruler point where the given thumb point to
     */
    private void setRangeValue(Thumb tb){
         int type=tb.getType() ;
         Range ex=this.ruler.getThumbs().getExtremeOfType(type) ;
         if(tb.getType() ==Thumb.WEST){ //thumb facing west, control axis tick range
              askIfZoomIn(ex);
             this.axis.setTargetAxisTickRange(ex);
         }
         else if (tb.getType() ==Thumb.EAST ){//thumb facing east, control line show range

             this.axis.setTargetAxisShowRange(ex);
         }


    }
    /**
     * When tick range is too small, it is hard to change it even smaller. Need zoom in
     * @param targetAxisTickRange
     */
    private void askIfZoomIn(Range targetAxisTickRange){
        float max = targetAxisTickRange.getMax();
        float min = targetAxisTickRange.getMin();

        float gvmax = this.ruler.getGraphicValueOf(max); // 
        float gvmin = this.ruler.getGraphicValueOf(min);

        float distance = Math.abs(gvmax-gvmin);
        if (false&&distance<=10){//10 pixel
            JOptionPane.showMessageDialog(axis, "Distance ="+distance+". Need zoom in?");
        }
    }

    private JPanel getZoomInPanel(Range targetAxisTickRange){
        ZoomAxisPanel p=new ZoomAxisPanel();
        return null;
    }

    /////////////////////////////////////////////////////////////////////////
    /// Thumb Listener Class
    /////////////////////////////////////////////////////////////////////////
    /**
     * Track Thumb movements.
     *
     * This inner class is marked &quot;public&quot; due to a compiler bug.
     * This class should be treated as a &quot;protected&quot; inner class.
     * Instantiate it only within subclasses of <Foo>.
     */
    public class ThumbListener extends MouseInputAdapter {
        public static final boolean DEBUG=false;
        private Point lastp=new Point();
        private Point cp=new Point();//current point
        Thumb actTmb;
        public void mousePressed(MouseEvent e) {

              int x=e.getX() ;
              int y=e.getY() ;
              this.cp.setLocation(x,y);
              actTmb =ruler.getThumb(x,y);  //active thumb
              if (actTmb!=null){
                //System.out.println("Active tmb:"+actTmb);
              }





         }
         public void mouseDragged(MouseEvent e) {
             this.updateLCpoint(e);
             if (actTmb!=null){
                int delta=cp.y-this.lastp.y;
                //dp{
                if (DEBUG){
                    //System.out.println("delta:"+delta);
                }//dp}
                //this.getValueOf(cp.y);  // mouse location!=thumb's location

                //actTmb.move(delta);  getPt().y+delta


                float value=ruler.getValueOf(actTmb.getPt().y+delta); //real value

                //value must be within the axis's tick range ->
                float tickMax=axis.getTickRange().getMax() ;
                float tickMin=axis.getTickRange().getMin() ;
                if (value >tickMax){
                    value=tickMax;
                }
                else if (value<tickMin){
                    value=tickMin;
                }
                //value must be within the axis's tick range <-

                actTmb.setValue(value);
                 setRangeValue(actTmb);// 
                 /*SwingUtilities.invokeLater(
                         new Runnable()
                 {
                             public void run()
                             {

                             }
                         });*/




                //this.setThumbValue(actTmb,value);
                //actTmb.setValue(value);     */
                axis.repaint() ;
             }
             //System.out.println("!! drag");
         }
         public void mouseMoved(MouseEvent e) {
         }
         public void mouseReleased(MouseEvent e) {
             //setRangeValue(actTmb);
             this.actTmb =null;

         }


         public void mouseEntered(MouseEvent e) {}
         public void mouseExited(MouseEvent e) {}
         public void mouseClicked(MouseEvent e) {}
        /**
          *  update value of last point and current point
          */
        private void updateLCpoint(int x, int y){
            this.lastp.setLocation(this.cp );
            this.cp.setLocation(x,y);
        }
        private void updateLCpoint(MouseEvent e){
            int x=e.getX() ;
            int y=e.getY() ;
            this.lastp.setLocation(this.cp );
            this.cp.setLocation(x,y);
        }
    }
    /*******************************************************************************************************
     *                Data model listener
     ******************************************************************************************************
    public class ChangeHandler implements ChangeListener {
        public void stateChanged(ChangeEvent e)                {

	        updateRuler();
            if (axis!=null)
            axis.repaint();

        }
    }      */
    static class ZoomAxisPanel extends javax.swing.JPanel {

    /** Creates new form ZoomAxisPanel */
    public ZoomAxisPanel() {
        initComponents();
    }

        public JTextField getMinFd() {
            return minFd;
        }

        public void setMin(float v) {
            
            this.minFd = minFd;
        }

        public JTextField getMaxFd() {
            return maxFd;
        }

        public void setMaxFd(JTextField maxFd) {
            this.maxFd = maxFd;
        }

        public JCheckBox getNoShowChk() {
            return noShowChk;
        }

        public void setNoShowChk(JCheckBox noShowChk) {
            this.noShowChk = noShowChk;
        }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        line1 = new javax.swing.JLabel();
        minL = new javax.swing.JLabel();
        minFd = new javax.swing.JTextField();
        maxFd = new javax.swing.JTextField();
        maxL = new javax.swing.JLabel();
        noShowChk = new javax.swing.JCheckBox();
        line2 = new javax.swing.JLabel();
        line3 = new javax.swing.JLabel();

        setLayout(new java.awt.GridBagLayout());

        setBorder(new javax.swing.border.TitledBorder(null, "Zoom", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("MS Sans Serif", 1, 14), new java.awt.Color(102, 102, 255)));
        line1.setFont(new java.awt.Font("Times New Roman", 0, 14));
        line1.setText("To easily operate on the handlers, we recommend to zoom in  ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.ipadx = 41;
        gridBagConstraints.insets = new java.awt.Insets(0, 20, 0, 15);
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(line1, gridBagConstraints);

        minL.setFont(new java.awt.Font("MS Sans Serif", 1, 11));
        minL.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        minL.setText("Min");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 20, 0, 0);
        gridBagConstraints.weightx = 0.2;
        add(minL, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        add(minFd, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 15);
        gridBagConstraints.weightx = 1.0;
        add(maxFd, gridBagConstraints);

        maxL.setFont(new java.awt.Font("MS Sans Serif", 1, 11));
        maxL.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        maxL.setText("Max");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0);
        gridBagConstraints.weightx = 0.2;
        add(maxL, gridBagConstraints);

        noShowChk.setText("Don't show me the dialog anymore.");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(7, 16, 7, 11);
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(noShowChk, gridBagConstraints);

        line2.setFont(new java.awt.Font("Times New Roman", 0, 14));
        line2.setText("by setting the following values");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(2, 21, 18, 16);
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        add(line2, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(0, 22, 0, 17);
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        add(line3, gridBagConstraints);

    }


    // Variables declaration - do not modify
    private javax.swing.JCheckBox noShowChk;
    private javax.swing.JTextField minFd;
    private javax.swing.JTextField maxFd;
    private javax.swing.JLabel line1;
    private javax.swing.JLabel line2;
    private javax.swing.JLabel line3;
    private javax.swing.JLabel maxL;
    private javax.swing.JLabel minL;
    // End of variables declaration

}



}
